<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>BlockPy Replay</title>
    
    <link rel="stylesheet" href="libs/bootstrap.min.css">
    <link rel="stylesheet" href="libs/codemirror/codemirror.css">
    <link rel="stylesheet" href="libs/font-awesome.min.css">
    <link rel="stylesheet" href="libs/summernote/summernote.css">
    <link rel="stylesheet" href="libs/multi-select.css">
    <link rel="stylesheet" href="src/blockpy.css">
    <!--<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">-->
    
    <!-- JQuery, D3, Math.js, Bootstrap -->
    <script type="text/javascript" src="libs/jquery.js"></script>
    <script type="text/javascript" src="libs/jquery-ui.min.js"></script>
    <script type="text/javascript" src="libs/jquery.hotkeys.js"></script>
    <script type="text/javascript" src="libs/jquery.multi-select.js"></script>
    <script type="text/javascript" src="libs/d3.min.js"></script>
    <script type="text/javascript" src="libs/math.0.19.0.min.js"></script>
    <script type="text/javascript" src="libs/bootstrap.min.js"></script>
    <script type="text/javascript" src="libs/bootstrap-wysiwyg.js"></script>
    <script type="text/javascript" src="libs/mindmup-editabletable.js"></script>
    <script type="text/javascript" src="libs/codemirror/codemirror.js"></script>
    <script type="text/javascript" src="libs/codemirror/python.js"></script>
    <script type="text/javascript" src="libs/codemirror/htmlmixed.js"></script>
    <script type="text/javascript" src="libs/codemirror/xml.js"></script>
    <script type="text/javascript" src="libs/knockout-3.4.0.js"></script>
    
    <!-- Summernote, a rich text editor -->
    <script type="text/javascript" src="libs/summernote/summernote.min.js"></script>
    <script type="text/javascript" src="libs/summernote/summernote-ext-hint.js"></script>
    <script type="text/javascript" src="libs/summernote/summernote-ext-video.js"></script>
    
    <!-- Blockly -->
    <script type="text/javascript" src="blockly/blockly_uncompressed.js"></script>
    <script type="text/javascript" src="blockly/blocks_compressed.js"></script>
    <script type="text/javascript" src="blockly/python_compressed.js"></script>
    <script type="text/javascript" src="blockly/pseudo_compressed.js"></script>
    <script type="text/javascript" src="blockly/javascript_compressed.js"></script>
    <script type="text/javascript" src="blockly/msg/js/en.js"></script>
    
    <!-- Skulpt -->
    <script type="text/javascript" src="skulpt/dist/skulpt.min.js"></script>
    <script type="text/javascript" src="skulpt/dist/skulpt-stdlib.js"></script>
    
    <!-- Source Code -->
    <script type="text/javascript" src="src/utilities.js"></script>
    <script type="text/javascript" src="src/python_errors.js"></script>
    <script type="text/javascript" src="src/ast_node_visitor.js"></script>
    <script type="text/javascript" src="src/abstract_interpreter.js"></script>
    <script type="text/javascript" src="src/abstract_interpreter_definitions.js"></script>
    <script type="text/javascript" src="src/abstract_interpreter_tests.js"></script>
    <script type="text/javascript" src="src/python_to_blockly.js"></script>
    <script type="text/javascript" src="src/imported.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/class.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/comment.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/comprehensions.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/dict.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/if.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/io.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/lists.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/sets.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/loops.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/parking.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/tuple.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/turtles.js"></script>
    <script type="text/javascript" src="src/blockly_blocks/text.js"></script>
    <script type="text/javascript" src="src/dialog.js"></script>
    <script type="text/javascript" src="src/storage.js"></script>
    <script type="text/javascript" src="src/printer.js"></script>
    <script type="text/javascript" src="src/interface.js"></script>
    <script type="text/javascript" src="src/server.js"></script>
    <script type="text/javascript" src="src/english.js"></script>
    <script type="text/javascript" src="src/corgis.js"></script>
    <script type="text/javascript" src="src/history.js"></script>
    <script type="text/javascript" src="src/presentation.js"></script>
    <script type="text/javascript" src="src/editor.js"></script>
    <script type="text/javascript" src="src/feedback.js"></script>
    <script type="text/javascript" src="src/toolbar.js"></script>

    <script type="text/javascript" src="src/treeMatching.js"></script>
    <script type="text/javascript" src="src/sk_mod_instructor_extended.js"></script>
    <script type="text/javascript" src="src/sk_mod_instructor.js"></script>
    <script type="text/javascript" src="src/engine.js"></script>
    <script type="text/javascript" src="src/main.js"></script>
    
    <!--<script type="text/javascript" src="test_corgis/blockpy/tate/tate_blockly.js"></script>
    <script type="text/javascript" src="test_corgis/blockpy/tate/tate_skulpt.js"></script>
    <script type="text/javascript" src="test_corgis/blockpy/tate/tate_dataset.js"></script>-->
    
    <style>

    </style>
    <script>
    $(document).ready(function() {
        blockpy = new BlockPy({
            'blocklyPath': "blockly/",
            'attachmentPoint': document.getElementById('blockpy-div'),
            'instructor': true,
            'developer': true,
            'editor': 'Text',
            'urls': {
                'import_datasets': 'https://think.cs.vt.edu/blockpy/load_corgis/',
                //'walk_old_code': 'http://localhost:8000/walk_code/',
                //'log_event': 'http://localhost:8000/save_events/'
                /*'save_code': 'http://localhost:8000/save_code/',
                'save_success': 'http://localhost:8000/submit_grade/',
                'log_event': 'http://localhost:8000/save_events/'*/
            }
        });
        blockpy.setAssignment(
            // settings
            {
                'editor': 'Text',
                'read_only': false,
                'disable_semantic_errors': false,
            },
            // assignment
            {
                'introduction': "Welcome to BlockPy. Try running the code below.",
                'name': "#1.2",
                'give_feedback': 'import instructor_histogram as ins_hist\nimport instructor_append as ins_app\nimport instructor_iteration as ins_iter\nimport instructor_filter as ins_filt\nimport iteration_context as ins_cont\nins_app.missing_append_in_iteration()\nins_app.wrong_not_append_to_list()\nins_app.missing_append_list_initialization()\nins_app.wrong_append_list_initiatization()\nins_app.append_list_wrong_slot()\n',
                'parsons': false,
                'starting_code': '',
                'importable': true,
                'initial_view': 'Blocks',
                'modules': {
                    'added': ['Functions', 'Data - Weather'],
                    'removed': []
                }
            },
            // programs
            {
                '__main__': 'import matplotlib.pyplot as plt\nquakes = [1,2,3,4]\nquakes_in_miles = []\nfor quake in quakes:\n    quakes_in_miles.append(quake * 0.62)\nplt.hist(quakes_in_miles)\nplt.xlabel("Depth in Miles")\nplt.ylabel("Number of Earthquakes")\nplt.title("Distribution of Depth in Miles of Earthquakes")\nplt.show()\n'
            }
        )
        
        function inIframe () {
            try {
                return window.self !== window.top;
            } catch (e) {
                return true;
            }
        }
        if (inIframe()) {
            $("#blockpy-container").width("100%");
        }

        function updatePauseButton(){
            if(global_isPaused){
                document.getElementById("pause-button").innerHTML = "Play";
            }else{
                document.getElementById("pause-button").innerHTML = "Pause";
            }
        };

        var global_isPaused = false;
        const FORWARD_SCRUB = "forward";
        const BACKWARD_SCRUB = "backward";
        const STOP_SCRUB = "stop"
        var global_scrubing = STOP_SCRUB;
        var speed = 50;
        document.onkeydown = navigationStroke;
        
        function pauseEvent(){
            global_isPaused = !global_isPaused;
            updatePauseButton();
        }
        function forwardEvent(){
            global_isPaused = true;
            global_scrubing = FORWARD_SCRUB;
            updatePauseButton();
        }
        function backEvent(){
            global_isPaused = true;
            global_scrubing = BACKWARD_SCRUB;
            updatePauseButton();
        }
        function navigationStroke(key){
            var KeyNavigationEnabled = document.getElementById("myCheck").checked;
            if(KeyNavigationEnabled == true){
                key = key || window.event;
                if (key.keyCode == '80') {
                    // p is pressed
                    pauseEvent();
                }
                else if (key.keyCode == '37') {
                   // left arrow
                   backEvent();
                }
                else if (key.keyCode == '39') {
                   // right arrow
                   forwardEvent();
                }
            }
        }

        $('#speed-slider').change(function() {
            var sliderValue = document.getElementById("speed-slider").value;
            speed = 100 - document.getElementById("speed-slider").value;
            document.getElementById("sliderValue").innerHTML = sliderValue;
        });

        $('#pause-button').click(function() {
            global_isPaused = !global_isPaused;
            updatePauseButton();
        });

        $('#forward-button').click(function() {
            forwardEvent();
        });

        $('#backward-button').click(function() {
            backEvent();
        });
        
        function handleCodeEvents(record){
            switch (record.action.toLowerCase()) {
                case "set":
                    blockpy.model.programs['__main__'](record.body);
                    blockpy.components.editor.updateBlocks();
                    break;
                }
        }

        function executeLastCodeEvent(pastRecords){
            var codeEvent = null;
            for(i = pastRecords.length-1; i >= 0; i--){
                var rawRecord = pastRecords[i];
                record = JSON.parse(rawRecord);
                if(record.event.toLowerCase() == "code"){
                    codeEvent = record;
                    break;
                }
            }
            if(codeEvent != null){
                handleCodeEvents(codeEvent);
            }
        }

        function handleFeedbackEvents(record){
            var messages = record.body.split("\n");
            var detailError = messages[0];
            var bodyMessage = "";
            var regex = /line (\d{1,})/i;
            for(i = 1; i < messages.length; i++){
                bodyMessage += messages[i];
            }
            var results = regex.exec(bodyMessage);
            var line = results != null && results.length > 1 ? results[1] : null;
            try{
                switch (record.action.toLowerCase()) {
                    case "success":
                        blockpy.components.feedback.complete(detailError, bodyMessage, line);
                        break;
                    case "editor error":
                        blockpy.components.feedback.editorError(detailError, bodyMessage, line);
                        break;
                    case "no errors":
                        blockpy.components.feedback.noErrors(detailError, bodyMessage, line);
                        break;
                    case "syntax error":
                        blockpy.components.feedback.syntaxError(detailError, bodyMessage, line);
                        break;
                    case "semantic error":
                        blockpy.components.feedback.semanticError(detailError, bodyMessage, line);
                        break;
                    case "internal error":
                        blockpy.components.feedback.internalError(detailError, bodyMessage, line);
                        break;
                    case "instructor feedback":
                        blockpy.components.feedback.instructorFeedback(detailError, bodyMessage, line);
                        break;
                    case "empty program":
                        blockpy.components.feedback.emptyProgram(detailError, bodyMessage, line);
                        break;
                    default:
                        console.log(record.action.toLowerCase());
                        break;
                    // ...
                }
            }catch(err){
                console.error(err);
            }
        };


        $('#replay-button').click(function() {
            var records = $('#replay-data').val().split(/\r?\n/);
            var previousTime = null;
            var pastRecords = [];
            var goingBackwards = false;
            var clearRunFlag = false;
            function processAnother(recordsLeft) {
                var gap = 100;
                var moveForward = true;
                if(global_isPaused){
                    switch(global_scrubing){
                        case BACKWARD_SCRUB:
                            if(pastRecords.length > 1){
                                blockpy.components.feedback.clearEditorErrors();
                                blockpy.components.feedback.clear();
                                recordsLeft.unshift(pastRecords.pop());
                                recordsLeft.unshift(pastRecords.pop());
                                goingBackwards = true;
                                //TODO: Handle when going backwards to a feedback event
                            }else{
                                moveForward = false;
                            }
                            //NOTE: This cascades into FORWARD_SCRUB
                        case FORWARD_SCRUB:
                            global_scrubing = STOP_SCRUB;
                            previousTime = null;
                            break;
                        default:
                        moveForward = false;
                        break;
                    };
                }
                if(moveForward && recordsLeft.length > 0){
                    blockpy.components.feedback.clearEditorErrors();
                    blockpy.components.feedback.clear();
                    var rawRecord = recordsLeft.shift();
                    var record = JSON.parse(rawRecord);
                    pastRecords.push(rawRecord);
                    switch (record.event.toLowerCase()) {
                        case "code":
                            handleCodeEvents(record);
                            break;
                        case "feedback":
                            if(goingBackwards){
                                executeLastCodeEvent(pastRecords);
                            }
                            handleFeedbackEvents(record);
                            break;
                    }
                    var cur_time = new Date(record.time*1000);
                    if(!global_isPaused){
                        gap = previousTime != null ? record.time - previousTime : 0;
                        gap = (gap > 2000 ? 2000 : gap)*speed;
                        previousTime = record.time;
                        //var cur_time = new Date(record.time*1000);
                        //var cur_time = record.time;
                        //cur_time = cur_time.getHours();
                        console.log(gap + ": " + cur_time.getHours() + ":" + cur_time.getMinutes() + ":" + cur_time.getSeconds() + ":" + cur_time.getMilliseconds() + "/" + record.time + ", ass: " + record.assignment + ", user: " + record.user);
                    }else{
                        console.log("freeze frame" + ": " + cur_time.getHours() + ":" + cur_time.getMinutes() + ":" + cur_time.getSeconds() + ":" + cur_time.getMilliseconds() + "/" + record.time + ", ass:" + record.assignment + ", user: " + record.user);
                    }
                    //blockpy.components.editor.getPngFromBlocks
                }
                if(!clearRunFlag){
                   setTimeout(function() {processAnother(recordsLeft)}, gap);
                }
            }
            processAnother(records);
        });
    });
    </script>

</head>
<body>
<div style="width:900px;  margin:0 auto;" id='blockpy-container'> <!-- 900px -->
    <!-- Replay stuff -->
    <textarea class="form-control" rows="3" id='replay-data'></textarea>
    <button type='button' class='btn btn-submit' id='replay-button'>Replay</button>
    <button type='button' class='btn btn-submit' id='pause-button'>Pause</button>
    <button type='button' class='btn btn-submit' id='backward-button'>Backward</button>
    <button type='button' class='btn btn-submit' id='forward-button'>Forward</button>
    KeyNavigation: <input type="checkbox" id="myCheck" checked="check">
    <input type="range" id="speed-slider" value="50" min="1" max="100">
    <p id="sliderValue" value="50"></p>
    <div id="blockpy-div" style='height:100%'></div>
</div>

<script>

</script>

</body>
</html>
